import path from 'path';
import fs from 'fs';
import Api from '../request/api.js';
import { sleep, log, md5, getHallId } from '../utils/utils.js';
import process from 'process';
import dotenv from 'dotenv';
import puppeteer from 'puppeteer-extra';
import axios from 'axios';
import { PayType, TicketChannel } from '../constant/index.js';
import { Encrypt } from '../utils/leyingSecret.js';

const ua =
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 MicroMessenger/6.8.0(0x16080000) NetType/WIFI MiniProgramEnv/Mac MacWechat/WMPF XWEB/30626';

// const waitSelectTime = 300000; // 选座等待时间
dotenv.config();
const {
  EXECUTABLE_PATH,
  CINEMA_ACC_ID,
  CINEMA_TOKEN = '',
  CINEMA_ACCOUNT,
  CINEMA_CITYCODE,
  CINEMA_PWD,
  CINEMA_LINKID,
  CINEMA_CODE,
} = process.env;

const API = new Api();

export default class Leying {
  // token
  loginToken = CINEMA_TOKEN;

  // 用户信息
  ticketUser = {};

  // 会员卡信息
  memberCardInfo = null;

  // 座位
  selectSeatList = '';

  // 接口请求头
  requestHeader = {
    'User-Agent': ua,
    Accept: 'application/json',
    'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
    'Content-Type': 'application/x-www-form-urlencoded',
    'gray-lease-code': 'GS',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-site',
    Pragma: 'no-cache',
    'Cache-Control': 'no-cache',
  };

  // 订单信息
  order = {
    state: '',
    ticketCode: '',
    paramDetail: {}, // 订单详情参数
  };

  // 锁定订单ID
  lockOrderId = '';

  // 创建订单ID
  orderConfirmId = '';

  // data
  dataJson = null;

  // 写入本地保存
  setOrderState(state, ticketCode = '', paramDetail = {}) {
    if (ticketCode) {
      this.order.ticketCode = ticketCode;
    }
    this.order.paramDetail = { ...this.order.paramDetail, ...paramDetail };
    this.order.state = state;

    fs.writeFileSync(
      './orderJson/' + this.dataJson.sn + '.json',
      JSON.stringify(this.order, null, 2),
      {
        flag: 'w',
      },
      (err) => {
        if (err) {
          console.error('订单状态写入', err);
        }
      }
    );
  }

  // 订单开始 初始化
  async orderStart(dataJson) {
    // 检查登录
    this.ticketUser = {
      cinemaAccId: CINEMA_ACC_ID,
      cinemaAccount: CINEMA_ACCOUNT,
      cinemaAccountPwd: CINEMA_PWD,
    };

    this.order = {
      state: '',
      ticketCode: '',
      paramDetail: {},
    };
    this.dataJson = dataJson;
    this.selectSeatList = null;
    this.memberCardInfo = null;
    this.orderConfirmId = '';
    this.lockOrderId = '';
  }

  // 获取座位信息
  async getSeat() {
    // 等待选座
    const dataJson = this.dataJson;
    const { scheduleKey } = dataJson.showObj;
    const resData = await this.requestPageApi('play/seat', {
      show_id: scheduleKey,
    });
    if (
      !resData.play_data ||
      !resData.play_data.seat_data ||
      resData.play_data.seat_data.length === 0
    ) {
      log('场次数据获取失败 ' + JSON.stringify(resData), 'error');
      throw new Error('场次选择失败');
    }

    const { play_date, start_time } = resData.play_data;
    //  "play_date": "2023-07-12",
    //  "start_time": "15:20:00",
    // 判断时间是否正确
    const showTime = new Date(`${play_date} ${start_time}`);
    if (showTime.getTime() !== dataJson.showTimestamp) {
      throw new Error('场次选择失败[RETRY]');
    }

    // 订单座位
    // 座位转成 [[11,2],[11,3]]
    const seatListArr = this.dataJson.seatList.map((i) =>
      i
        .match(/[\d|A-Za-z]+/g)
        .map((d) => (isNaN(Number(d)) ? d.toLocaleUpperCase() : Number(d)))
    );
    // const seatListArr = dataJson.seatList;
    // 获取座位
    const seatList = [];
    const seats = resData.play_data.seat_data;
    // ['6237', '1', '0', '2', '11', 'A排6号', '', '375', '1'];
    // Sitid, Type, status, vertical, horizontal,Sitname,Relation_sit,Priority,FenquId
    for (const seat of seats) {
      const seatArr = seat[5]
        .match(/[\d|A-Za-z]+/g)
        .map((d) => (isNaN(Number(d)) ? d.toLocaleUpperCase() : Number(d)));
      if (
        !seatListArr.find((st) => st[0] === seatArr[0] && st[1] === seatArr[1])
      ) {
        continue;
      }

      if (seat[2] !== '0') {
        throw new Error(
          `座位已被锁定 ${this.dataJson.from} ${this.dataJson.cinemaName}`
        );
      }

      seatList.push({
        sectionNo: seat[0],
        seatName: seat[5],
        row: seat[3],
        col: seat[4],
      });
    }
    if (seatList.length < dataJson.seatList.length) {
      throw new Error('座位未找到');
    }

    this.selectSeatList = seatList;
    return seatList;
  }

  // 锁定座位
  /**
   * [{"areaId":"0","column":3,"columnName":"2","flag":0,"name":"1排2座","row":1,"rowName":"1","seatId":"000000031026-1-3","status":1}]
   */
  async lockSeat() {
    const seatList = this.selectSeatList;
    const dataJson = this.dataJson;
    const { scheduleKey } = dataJson.showObj;
    // 座位锁定请求
    const lockBizData = await this.requestPageApi('user/lock-seat', {
      force_lock: '-1',
      seat_ids: seatList.map((s) => s.sectionNo).join(','),
      show_id: scheduleKey,
    });
    if (lockBizData && lockBizData.lock_flag) {
      // 成功锁座
      log('座位锁定成功');
      this.lockOrderId = lockBizData.lock_flag;
    } else {
      // 锁座失败
      log('座位锁定请求失败 ' + JSON.stringify(lockBizData), 'error');
      throw new Error('锁座失败[RETRY]:' + (lockBizData.msg || ''));
    }
  }

  // 提交订单信息
  async submitOrderInfo(cinemaInfo) {
    const selectSeatList = this.selectSeatList;
    // 支付方式
    let payType;
    let costFee = 999999;
    if (cinemaInfo.settle_type == PayType.BALANCE) {
      ({ payType, costFee } = await this.getVipCost(
        selectSeatList,
        cinemaInfo
      ));
    } else if (cinemaInfo.settle_type == PayType.COUPON) {
      ({ payType, costFee } = this.getCouponCost(cinemaInfo));
    } else if (cinemaInfo.settle_type == PayType.E_TICKET) {
      ({ payType, costFee } = this.getETicketCost(cinemaInfo));
    } else {
      // 根据成本 选择支付方式
      if (cinemaInfo.vip_cost_ratio > 0) {
        // VIP
        ({ payType, costFee } = await this.getVipCost(
          selectSeatList,
          cinemaInfo
        ));
      }
      if (cinemaInfo.coupon_fee > 0) {
        // 线下券
        const { payType: pt, costFee: vipCostFee } =
          this.getCouponCost(cinemaInfo);
        if (vipCostFee < costFee) {
          costFee = vipCostFee;
          payType = pt;
        }
      }
      if (cinemaInfo.e_ticket_fee > 0) {
        // 优惠券
        const { payType: pt, costFee: vipCostFee } =
          this.getETicketCost(cinemaInfo);
        if (vipCostFee < costFee) {
          costFee = vipCostFee;
          payType = pt;
        }
      }
    }

    // 更新成本
    // log('更新成本 ' + JSON.stringify({ costFee, payType }));
    await API.updateOrderCost(this.dataJson.id, costFee || 999999);
    const sellAmount = Number(this.dataJson.sellAmount);
    // force_ticket是否强制出票
    if (sellAmount > 0 && sellAmount <= costFee && !cinemaInfo.force_ticket) {
      throw new Error(
        `成本高于报价[类型${payType}-成本${costFee}-报价${sellAmount}]`
      );
    }
    // 开始进行支付
    let payResult = false;
    if (payType === PayType.BALANCE) {
      // 使用会员卡余额
      payResult = await this.useVipBalance(selectSeatList, cinemaInfo);
    } else if (payType === PayType.COUPON) {
      // 使用线下券
      payResult = await this.useCoupon();
    } else if (payType === PayType.E_TICKET) {
      // 使用优惠券
      payResult = await this.useETicket(cinemaInfo);
    }
    if (!payResult) {
      throw new Error('支付失败-' + payType);
    }
    // 设置订单状态
    this.setOrderState('success', '', {
      costFee,
      payType,
      orderId: this.orderConfirmId,
    });

    // 从订单列表里获取订单信息
    return this.getOrderInfo();
  }

  // 获取会员卡信息
  async getCardInfo(selectSeatList) {
    if (this.memberCardInfo) {
      return this.memberCardInfo;
    }
    const dataJson = this.dataJson;
    const { scheduleKey } = dataJson.showObj;
    const requestParams = {
      additional_goods_info: '',
      goods_info: '',
      is_first: '1',
      option_goods_info: '',
      seat_ids: selectSeatList.map((s) => s.sectionNo).join(','),
      show_id: scheduleKey,
      update_time: '',
    };

    // 获取会员卡列表
    let cardBal = 0;
    const cardList = await this.requestPageApi('card/get-user-cinema-card', {});
    if (cardList && cardList.card_data && cardList.card_data.length > 0) {
      for (const card of cardList.card_data) {
        if (card.card_status === '1' && Number(card.balance) > cardBal) {
          requestParams.is_first = '0';
          requestParams.card_id = card.id;
          cardBal = Number(card.balance);
        }
      }
    }

    let calData = await this.requestPageApi(
      'v2/price/calculate',
      requestParams,
      'POST'
    );
    if (calData.errcode === '400005') {
      // 本卡在该影院下不可用
      requestParams.is_first = '1';
      delete requestParams.card_id;
      calData = await this.requestPageApi(
        'v2/price/calculate',
        requestParams,
        'POST'
      );
    }

    this.memberCardInfo =
      calData.price || calData.defaultCardPrice || calData.nonMemberPrice;
    log('获取会员卡 memberCardInfo值 ' + JSON.stringify(this.memberCardInfo));
    return this.memberCardInfo;
  }

  // VIP成本
  async getVipCost(selectSeatList, cinemaInfo) {
    // VIP
    const vipCardData = await this.getCardInfo(selectSeatList);
    let costFee = 999999;
    if (vipCardData && vipCardData.status === '1') {
      costFee = vipCardData.total_price * cinemaInfo.vip_cost_ratio;
    }
    return {
      payType: PayType.BALANCE,
      costFee: costFee || 999999,
    };
  }

  // 特惠券成本
  getETicketCost(cinemaInfo) {
    // 特惠券
    const ticketCount = this.dataJson.seatList.length;
    const { isSpec, weight } = this.dataJson.showObj;
    return {
      payType: PayType.E_TICKET,
      costFee: isSpec
        ? cinemaInfo.e_ticket_fee * weight * ticketCount
        : cinemaInfo.e_ticket_fee * ticketCount,
    };
  }

  // 使用特惠券
  async useETicket(cinemaInfo) {
    const selectSeatList = this.selectSeatList;
    const dataJson = this.dataJson;
    const { scheduleKey } = dataJson.showObj;
    const cardInfo = await this.getCardInfo(selectSeatList);
    const { default_card: defaultCard = {} } = cardInfo || {};
    if (!cardInfo) {
      throw new Error('会员卡数据为空，出票上限限制');
    }

    // 获取特惠券列表
    const couponListData = await this.requestPageApi(
      'coupon/get-list-when-pay',
      {
        card_id: defaultCard.id || '',
        goods_info: '',
        is_only_goods_type: '0',
        page: '1',
        price: `${cardInfo.ticket_price - cardInfo.total_service_fee}`,
        show_id: scheduleKey,
        use_strategy: cardInfo.promo_id || 0,
      }
    );
    log('获取特惠券列表 ' + JSON.stringify(couponListData));
    if (!couponListData || !couponListData.lists) {
      throw new Error('特惠券数据获取失败');
    }

    // 更新券数
    let useCouponNum = this.dataJson.seatList.length;
    const { isSpec, weight } = this.dataJson.showObj;
    if (isSpec) {
      // 特殊影厅
      useCouponNum = useCouponNum * weight;
    }
    const totalNeedCouponNum = useCouponNum;
    if (couponListData.total_num < useCouponNum) {
      throw new Error(
        `特惠券数量不足[${couponListData.total_num}-${useCouponNum}]`
      );
    }
    // 查找使用优惠券
    const ticketInfos = [];
    for (const couponInfo of couponListData.lists) {
      if (useCouponNum <= 0) {
        break;
      }
      if (couponInfo.status !== 'ok' || couponInfo.can_use !== '1') {
        continue;
      }
      ticketInfos.push(couponInfo);
      useCouponNum = useCouponNum - 1;
    }
    if (ticketInfos.length < totalNeedCouponNum) {
      throw new Error(
        `特惠券可用的券数不足[${ticketInfos.length}-${totalNeedCouponNum}]`
      );
    }

    // 验证优惠券
    const quanCodes = ticketInfos.map((t) => t.id);
    const validatorData = await this.requestPageApi(
      'v2/price/calculate',
      {
        additional_goods_info: '',
        card_id: defaultCard.id || '',
        coupon_id: quanCodes.join(','),
        goods_coupon_id: '',
        goods_info: '',
        is_first: '0',
        option_goods_info: '',
        seat_ids: selectSeatList.map((s) => s.sectionNo).join(','),
        show_id: scheduleKey,
        update_time: '',
      },
      'POST'
    );
    if (!validatorData || !validatorData.price) {
      log('特惠券验证失败 ' + JSON.stringify(validatorData));
      throw new Error('特惠券验券失败:' + validatorData.msg);
    }
    const createData = {
      additional_goods_info: '',
      companion_info: '',
      coupon_id: quanCodes.join(','),
      goods_coupon_id: '',
      goods_info: '',
      option_goods_info: '',
      pay_money: `${Number(validatorData.price.total_price)}`,
      phone: this.ticketUser.cinemaAccount,
      promo_id: validatorData.promo_id,
      seat_ids: selectSeatList.map((s) => s.sectionNo).join(','),
      seat_info: selectSeatList.map((s) => s.seatName).join(','),
      show_id: scheduleKey,
    };
    // if (validatorData.price.total_price > 0) {
    //   if (cardInfo.can_buy_with_online_pay !== '1') {
    //     throw new Error(
    //       '特惠券需要额外支付金额:' + validatorData.price.total_price
    //     );
    //   } else {
    if (defaultCard.id) {
      createData.card_id = defaultCard.id || '';
      createData.card_password = defaultCard.id && Encrypt(cinemaInfo.vip_pwd);
    }
    //   }
    // }

    // 创建订单
    const orderInfo = await this.requestPageApi(
      'v2/order/ng-create',
      createData,
      'POST'
    );
    if (!orderInfo || !orderInfo.order_num) {
      log('特惠券使用失败 ' + JSON.stringify(orderInfo));
      throw new Error('特惠券兑换失败[TRY] ' + orderInfo.msg);
    }
    // if (Number(orderInfo.order_price) > 0) {
    //   log('特惠券使用失败 ' + JSON.stringify(orderInfo));
    //   throw new Error('特惠券兑换失败 需额外支付:' + orderInfo.order_price);
    // }

    // 执行兑换
    const exchangeData = await this.requestPageApi('ticket/ng-buy', {
      // 写死不知道会不会有问题
      open_id: 'oI8bx5KC1_IJ31lLlu7r2feQlhkM',
      order_num: orderInfo.order_num,
      pay_money: Number(orderInfo.order_price),
      pay_type: '',
    });

    if (!exchangeData || exchangeData.order_status !== '1') {
      log('特惠券使用失败(执行) ' + JSON.stringify(exchangeData));
      throw new Error('特惠券执行使用失败[TRY] ' + (exchangeData.msg || ''));
    }

    this.orderConfirmId = orderInfo.order_num;

    // 更新券列表
    await API.uploadCoupon(
      couponListData.lists
        .filter((i) => !quanCodes.includes(i.id))
        .map((coupon) => ({
          type: 2,
          couponNo: coupon.id,
          status: coupon.status === 'ok' ? 1 : 2,
          timeStart: new Date(coupon.validate_date_start).getTime() / 1000,
          timeEnd:
            new Date(coupon.validate_date_end + ' 23:59:59').getTime() / 1000,
          couponVer: coupon.coupon_id || '',
          couponName: coupon.coupon_name || '',
          couponInfo: coupon.coupon_order_name || '',
        })),
      CINEMA_ACC_ID,
      CINEMA_ACCOUNT,
      TicketChannel.LEYING
    );

    await API.updateETicketNum(couponListData.total_num - useCouponNum);
    return true;
  }

  // 线下券成本
  getCouponCost(cinemaInfo) {
    // 线下券
    const ticketCount = this.dataJson.seatList.length;
    const { isSpec, weight, couponPlus = 0 } = this.dataJson.showObj;
    return {
      payType: PayType.COUPON,
      costFee: isSpec
        ? cinemaInfo.coupon_fee * weight * ticketCount + couponPlus
        : cinemaInfo.coupon_fee * ticketCount,
    };
  }

  // 使用线下券
  async useCoupon() {
    const selectSeatList = this.selectSeatList;
    // 获取线下券列表
    const couponListData = await this.requestPageApi(
      'v2/coupon/get-offline-coupon-list',
      {
        request_from: '1',
      }
    );
    if (!couponListData || !couponListData.list) {
      throw new Error('线下券数据获取失败[RETRY]');
    }

    // 更新券数
    let useCouponNum = this.dataJson.seatList.length;
    const { isSpec, weight } = this.dataJson.showObj;
    if (isSpec) {
      // 特殊影厅
      useCouponNum = useCouponNum * weight;
    }
    const totalNeedCouponNum = useCouponNum;
    if (couponListData.can_use_count < useCouponNum) {
      throw new Error(
        `线下券数量不足[${couponListData.can_use_count}-${useCouponNum}]`
      );
    }
    // 查找使用优惠券
    let ignoreCouponArr = [];
    const ignoreCoupon = await API.getSysConfig('LEYING_IGNORE_COUPON');
    if (ignoreCoupon) {
      ignoreCouponArr = ignoreCoupon.split('|');
    }
    const ticketInfos = [];
    for (const couponInfo of couponListData.list) {
      if (useCouponNum <= 0) {
        break;
      }
      if (couponInfo.status !== 'ok' || couponInfo.can_use !== '1') {
        continue;
      }
      // 过滤券
      if (ignoreCouponArr.includes(couponInfo.coupon_num)) {
        continue;
      }

      ticketInfos.push(couponInfo);
      useCouponNum = useCouponNum - 1;
    }
    if (ticketInfos.length < totalNeedCouponNum) {
      throw new Error(
        `线下券可用的券数不足[${ticketInfos.length}-${totalNeedCouponNum}]`
      );
    }

    // 验证优惠券
    const quanCodes = ticketInfos.map((t) => t.coupon_num);
    const dataJson = this.dataJson;
    const { scheduleKey } = dataJson.showObj;
    const validatorData = await this.requestPageApi(
      'v2/price/calculate',
      {
        additional_goods_info: '',
        goods_info: '',
        is_first: '0',
        member_coupon_id: '',
        option_goods_info: '',
        pver: '7.0',
        quan_code: quanCodes.join(','),
        seat_ids: selectSeatList.map((s) => s.sectionNo).join(','),
        show_id: scheduleKey,
        update_time: '',
      },
      'POST'
    );
    if (!validatorData || !validatorData.price) {
      log('线下券验证失败 ' + JSON.stringify(validatorData));
      throw new Error('验券失败[TRY]:' + validatorData.msg);
    }
    // if (validatorData.price.total_price > 0) {
    //   throw new Error(
    //     '线下券需要额外支付金额:' + validatorData.price.total_price
    //   );
    // }

    // 创建订单
    const orderInfo = await this.requestPageApi(
      'v2/order/ng-create',
      {
        additional_goods_info: '',
        companion_info: '',
        coupon: quanCodes.join(','),
        goods_info: '',
        option_goods_info: '',
        pay_money: Number(validatorData.price.total_price),
        phone: this.ticketUser.cinemaAccount,
        promo_id: '0',
        seat_ids: selectSeatList.map((s) => s.sectionNo).join(','),
        seat_info: selectSeatList.map((s) => s.seatName).join(','),
        show_id: scheduleKey,
      },
      'POST'
    );
    if (!orderInfo || !orderInfo.order_num) {
      log('线下券使用失败 ' + JSON.stringify(orderInfo));
      throw new Error('线下券兑换失败[TRY] ' + orderInfo.msg);
    }
    if (Number(orderInfo.order_price) > 0) {
      log('线下券使用失败 ' + JSON.stringify(orderInfo));
      throw new Error(
        '线下券兑换失败[TRY] 需额外支付:' + orderInfo.order_price
      );
    }

    // 执行兑换
    const exchangeData = await this.requestPageApi('ticket/ng-buy', {
      // 写死不知道会不会有问题
      open_id: 'oI8bx5KC1_IJ31lLlu7r2feQlhkM',
      order_num: orderInfo.order_num,
      pay_money: '0',
      pay_type: '',
    });

    if (!exchangeData || exchangeData.order_status !== '1') {
      log('线下券使用失败(执行) ' + JSON.stringify(exchangeData));
      throw new Error('线下券执行使用失败[TRY] ' + (exchangeData.msg || ''));
    }

    // 更新券列表
    await API.uploadCoupon(
      couponListData.list
        .filter((i) => !quanCodes.includes(i.coupon_num))
        .map((coupon) => ({
          type: 1,
          couponNo: coupon.coupon_num,
          status: coupon.status === 'ok' ? 1 : 2,
          timeStart: new Date(coupon.validate_date_start).getTime() / 1000,
          timeEnd:
            new Date(coupon.validate_date_end + ' 23:59:59').getTime() / 1000,
          couponVer: md5(coupon.coupon_info || 'x'),
          couponName: coupon.coupon_info || '',
          couponInfo: coupon.coupon_detail || '',
        })),
      CINEMA_ACC_ID,
      CINEMA_ACCOUNT,
      TicketChannel.LEYING
    );

    await API.updateCouponNum(couponListData.can_use_count - useCouponNum);

    this.orderConfirmId = orderInfo.order_num;
    return true;
  }

  // 使用VIP余额支付
  async useVipBalance(selectSeatList, cinemaInfo) {
    const dataJson = this.dataJson;
    const { scheduleKey } = dataJson.showObj;
    const vipCardData = await this.getCardInfo(selectSeatList);
    const { default_card: defaultCard } = vipCardData;

    if (!defaultCard) {
      log('未绑定默认会员卡' + JSON.stringify(vipCardData));
      throw new Error('未绑定默认会员卡');
    }
    if (Number(defaultCard.balance) < Number(vipCardData.total_price)) {
      throw new Error('会员卡余额不足');
    }

    // 创建订单
    const orderInfo = await this.requestPageApi(
      'v2/order/ng-create',
      {
        additional_goods_info: '',
        card_id: defaultCard.id,
        card_password: Encrypt(cinemaInfo.vip_pwd),
        companion_info: '',
        goods_info: '',
        option_goods_info: '',
        pay_money: `${Number(vipCardData.total_price)}`,
        phone: this.ticketUser.cinemaAccount,
        promo_id: vipCardData.promo_id,
        seat_ids: selectSeatList.map((s) => s.sectionNo).join(','),
        seat_info: selectSeatList.map((s) => s.seatName).join(','),
        show_id: scheduleKey,
      },
      'POST'
    );
    if (!orderInfo || !orderInfo.order_num) {
      log('会员卡支付失败：' + JSON.stringify(orderInfo));
      throw new Error('会员卡支付失败[TRY]：' + (orderInfo.msg || ''));
    }

    // 确认支付
    const payData = await this.requestPageApi('ticket/ng-buy', {
      // 写死不知道会不会有问题
      open_id: 'oI8bx5KC1_IJ31lLlu7r2feQlhkM',
      order_num: orderInfo.order_num,
      pay_money: Number(orderInfo.order_price),
      pay_type: '',
    });

    if (!payData || payData.order_status !== '1') {
      log('会员卡使用失败(执行) ' + JSON.stringify(payData));
      throw new Error('会员卡使用失败[TRY] ' + (payData.msg || ''));
    }
    this.orderConfirmId = orderInfo.order_num;

    // 更新余额
    await API.updateVipBalance(
      (defaultCard.balance - vipCardData.total_price).toFixed(2),
      defaultCard.id,
      defaultCard.level || '会员卡X'
    ).catch((e) => {
      log('更新会员卡余额失败：' + JSON.stringify(e));
    });
    return true;
  }

  // 获取订单信息
  async getOrderInfo() {
    const filePath = './orderJson/' + this.dataJson.sn + '.json';
    if (!fs.existsSync(filePath)) {
      return false;
    }
    const buffer = fs.readFileSync(filePath);
    const fileContent = buffer.toString();
    if (!fileContent) {
      return false;
    }
    const orderState = JSON.parse(fileContent);
    this.order = orderState;

    const orderDetailData = await this.requestPageApi(
      'order/get-my-order-result',
      {
        order_num: orderState.paramDetail.orderId,
        order_type: 'ticket',
        order_type_num: '1',
      }
    );
    if (!orderDetailData || orderDetailData.msg === '等待影院出票') {
      log(
        '获取订单详情失败 ' +
          JSON.stringify(orderState) +
          ' ' +
          JSON.stringify(orderDetailData)
      );
      throw new Error('获取订单详情失败[RETRY] ' + (orderDetailData.msg || ''));
    }
    if (!orderDetailData.qrcode) {
      throw new Error('下单失败[FAILED]:' + (orderDetailData.msg || ''));
    }

    let uploadLink = '';
    if (this.dataJson.screenshot) {
      // 上传截图
      uploadLink = await this.screenshotAndUpload(orderDetailData);
    }
    let ticketCode = orderDetailData.serial_number_1;
    if (orderDetailData.serial_number_2) {
      ticketCode +=
        orderDetailData.ticket_code_type === '0'
          ? orderDetailData.serial_number_2
          : '|' + orderDetailData.serial_number_2;
    }

    this.setOrderState('success', ticketCode);

    return {
      orderId: orderDetailData.order_num,
      payType: orderState.paramDetail.payType,
      ticketCode,
      uploadLink,
    };
  }

  // 截图上传
  async screenshotAndUpload(detail) {
    const sep = path.sep;
    const data = {
      mobile: detail.mobile,
      order_num: detail.order_num,
      movie_name: detail.movie_name,
      movie_img_url: detail.movie_img_url.replace('/', '/'),
      cinema_name: detail.cinema_name,
      hall_name: detail.hall_name,
      seat_info: detail.seat_info,
      start_date: detail.start_date,
      start_time: detail.start_time,
      create_time: detail.create_time,
      movie_format: detail.movie_format,
      msg: detail.msg,
      total_price: detail.total_price,
      serial_number_1:
        detail.ticket_code_type === '0'
          ? detail.qrcode
          : detail.serial_number_1,
      serial_number_2: detail.serial_number_2,
    //   qrcode: detail.qrcode.replace('|', ''),
      qrcode: detail.qrcode,
      ticket_code_type: detail.ticket_code_type,
      seats: detail.seats,
      message: detail.message,
      tel: detail.tel,
    };
    // 本地路径
    const url = `file://${path.resolve(
      './'
    )}${sep}html${sep}order-detail.html?data=${encodeURIComponent(
      JSON.stringify(data)
    )}`;
    // 初始化
    const browser = await puppeteer.launch({
      executablePath: EXECUTABLE_PATH,
      //设置超时时间
      timeout: 15000,
      ignoreHTTPSErrors: true,
      headless: true,
      args: ['--disable-dev-shm-usage', '--no-sandbox', '--disable-plugins'],
    });
    const page = await browser.newPage();
    await page.goto(url);
    await page.setViewport({
      width: 375,
      height: 590,
    });

    // 截图
    const screenshotPath = './screenshot/' + this.dataJson.sn + '.png';
    await page.screenshot({
      path: screenshotPath,
    });
    await browser.close();

    // 上传截图
    return await API.uploadScreenshot(screenshotPath);
  }

  // 订单取消
  async cancelOrder() {
    if (this.orderConfirmId) {
      // 解锁请求
      return await this.requestPageApi('order/cancel-my-order', {
        id: this.orderConfirmId,
        type: '1',
      });
    }
    return true;
  }

  // 解锁座位
  async unlockSeat() {
    if (this.lockOrderId) {
      const selectSeatList = this.selectSeatList;
      const dataJson = this.dataJson;
      const { scheduleKey } = dataJson.showObj;
      // 解锁请求
      return await this.requestPageApi('user/unlock-seat', {
        orderNo: this.lockOrderId,
        orderType: '',
        lock_flag: this.lockOrderId,
        seat_ids: selectSeatList.map((s) => s.sectionNo).join(','),
        show_id: scheduleKey,
      });
    }
    return true;
  }

  // 页面接口请求
  async requestPageApi(path, data = {}, method = 'GET') {
    let url = `https://group.leying.com/${path}`;
    // 设置影院ID;
    let requestParams = {
      client_id: '',
      session_id: '',
      pver: '8.0',
      ver: '7.5.0',
      width: '240',
      //   source: 105001, // app
      source: '4', // 小程序
      group: CINEMA_CODE,
      cinema_id: CINEMA_LINKID,
      city_id: CINEMA_CITYCODE || '',
      session_id: this.loginToken,
      ...data,
    };
    // 签名
    const dataKeys = Object.keys(requestParams);
    dataKeys.sort(); // 按字母排序
    const postData = dataKeys.map((k) => `${k}=${requestParams[k]}`).join('&');
    // const sig = md5(md5(postData) + 'e48955751516cb79639e9c00c80b');
    const sig = md5(md5(postData) + 'cf0e5311eaffda07c28253e6916c7cf3');
    const requestParamStr = postData + '&.sig=' + sig;

    let requestBody = '';
    let header = {};
    if (method.toLocaleUpperCase() === 'POST') {
      requestBody = requestParamStr;
      requestParams = {};
      header = {
        'content-type': 'application/x-www-form-urlencoded',
      };
    } else {
      url = url + '?' + requestParamStr;
    }

    const res = await axios
      .request({
        url,
        method,
        data: requestBody,
        timeout: 15000,
        headers: {
          Host: 'group.leying.com',
          referer:
            'https://servicewechat.com/wx1e342ace9a26eb02/39/page-frame.html',
          xweb_xhr: '1',
          accept: '*/*',
          'sec-fetch-mode': 'cors',
          'sec-fetch-dest': 'empty',
          'accept-language': 'zh-CN,zh',
          'Sec-Fetch-Site': 'same-site',
          'User-Agent': ua,
          timestamp: `${Date.now()}`,
          'content-type': 'application/json',
          ...header,
        },
      })
      .catch((e) => {
        log(
          `乐影请求接口[${url}]异常 ${JSON.stringify(
            requestBody
          )} ${JSON.stringify(e)}`,
          'error'
        );
        return {
          status: -2, // 超时
          data: {
            status: -101,
            msg: e.message,
          },
        };
      });

    if (!res.data || res.data.status != 1) {
      log(
        `乐影请求接口[${url}]出错-${res.status} ${JSON.stringify(
          requestBody
        )} ${JSON.stringify(res.data)}`,
        'error'
      );
      if (res.data && res.data.errcode === '205') {
        // 登录态失效
        this.ticketUser.cinemaAccId &&
          (await API.authExpire(this.ticketUser.cinemaAccId));
        throw new Error('账号登录失效');
      }
      return res.data;
    }

    return res.data.data;
  }

  // 订单回退
  async orderRollback(dataJson) {
    log('回调订单状态,出票失败');
    // 订单锁定取消
    await API.orderRollback(dataJson.id, dataJson.msg).catch((e) =>
      console.error('取消订单请求异常', e)
    );
    if (this.orderConfirmId) {
      // 创建订单成功 付款失败
      const cancelRes = await this.cancelOrder();
      log(`取消订单:${this.orderConfirmId} ${JSON.stringify(cancelRes)}`);
    } else if (this.lockOrderId) {
      // 仅仅是座位锁定成功 订单取消锁定
      const unlockRes = await this.unlockSeat();
      log(`解锁座位:${this.lockOrderId} ${JSON.stringify(unlockRes)}`);
    }

    return true;
  }

  // 更新账户场次信息
  async updateShow(taskData) {
    // 检查登录
    this.ticketUser = {
      cinemaAccId: taskData.account_id,
      cinemaAccount: taskData.account,
      cinemaAccountPwd: taskData.pwd,
    };

    const shows = await this.requestPageApi('cinema/play-info', {
      city_id: 500,
      group: taskData.cinemas_code,
      cinema_id: taskData.cinema_data.linkid,
      session_id: taskData.login_token,
    });
    if (!shows || !shows.movie_data) {
      log('更新场次失败 ' + JSON.stringify(shows), 'error');
      await sleep(1000);
      return false;
    }

    const filmMap = {};
    for (const l of shows.movie_data) {
      const filmName = l.movie_name;
      if (!filmMap[filmName]) {
        filmMap[filmName] = [];
      }
      for (const showDay in l.shows) {
        for (const schedule of l.shows[showDay]) {
          const showTime = `${showDay} ${schedule.start_time}:00`;
          filmMap[filmName].push({
            showTime,
            isSpec: ['IMAX', '4D', 'VIP'].some((w) =>
              schedule.hall_name.includes(w)
            ),
            hallId: getHallId(schedule.hall_name, taskData.cinema_data.linkid),
            scheduleKey: schedule.show_id,
            showNo: schedule.show_id,
            hallName: schedule.hall_name,
            displayPrice:
              schedule.member_price > 0
                ? Math.round(
                    schedule.member_price * taskData['vip_cost_ratio'] * 100
                  )
                : schedule.nonmember_price * 100, // 会员卡价格*系数
            originalStandardPrice: schedule.market_price * 100, // 标准价格
            standardPrice: schedule.nonmember_price * 100, // 展示原价
            lowestPrice: schedule.price * 100, // 发行价
            ticketFee: 0, // 影院手续费
          });
        }
      }
    }

    await API.updateShowlist(
      taskData.cinema_id,
      taskData.account_id,
      taskData.vip_price_status,
      filmMap
    );

    log(
      `${taskData['cinema_name']}[${taskData['cinemas_code']}] 场次数据更新成功[${taskData.account}]`
    );
  }

  // 更新院线
  async updateCinemas(taskData) {
    // https://group.leying.com/city/list?.sig=51ea3ed272ec087838b1146f21203d9f&cinema_id=&city_id=500&client_id=&group=10000&session_id=&source=105001&ver=7.4.5
    const allCitys = await this.requestPageApi('city/list', {
      cinema_id: '',
      city_id: 500,
      group: taskData.cinemas_code,
    });
    const cityCinemasMap = [];
    for (const city of allCitys.all_city) {
      await sleep(100);
      const cinemas = await this.requestPageApi('cinema/list', {
        cinema_id: '',
        city_id: city.id,
        group: taskData.cinemas_code,
      });

      if (!cinemas || !Array.isArray(cinemas.cinema_data)) {
        continue;
      }

      cinemas.cinema_data.forEach((ele) => {
        cityCinemasMap.push({
          address: ele.address,
          cityCode: city.id,
          cityName: city.name,
          cinemaName: ele.name,
          cinemaLinkId: ele.id,
        });
      });
    }
    await API.updateCinemasData(
      taskData.id,
      taskData.vip_price_status,
      cityCinemasMap
    );

    log(
      `${taskData['cinemas_name']}[${taskData['cinemas_code']}] 院线数据更新成功`
    );
  }
}
